﻿using System;
using System.Collections.Generic;
using System.Linq;
using DeepEarth.Core;

namespace DeepEarth.Map.Core
{
	public static class LocationExtensions
	{
		/// <summary>
		/// Calculates the outer rectangle containing all the locations in the <paramref name="locations"/> collection.
		/// </summary>
		/// <param name="locations">The locations collection.</param>
		/// <returns>The rectangle containing all the locations in the <paramref name="locations"/> collection.</returns>
		/// <exception cref="ArgumentNullException">when <paramref name="locations"/> are not specified.</exception>
		public static LocationRectangle GetOuterRectangle(this IEnumerable<Location> locations)
		{
			if (locations == null) throw new ArgumentNullException("locations");

			var allLocations = locations.ToList();

			var nwCorner = new Location(allLocations.Select(x => x.Latitude).Max(),
				allLocations.Select(x => x.Longitude).Min()
				);
			var seCorner = new Location(allLocations.Select(x => x.Latitude).Min(),
				allLocations.Select(x => x.Longitude).Max()
				);

			return new LocationRectangle(nwCorner, seCorner);
		}


		/// <summary>
		/// Calculates the outer rectangle containing all the locations in the <paramref name="locations"/> collection
		/// and scales it by <paramref name="scaleFactor"/>.
		/// </summary>
		/// <param name="locations">The locations collection.</param>
		/// <param name="scaleFactor">The scale factor.</param>
		/// <returns>The rectangle containing all the locations in the <paramref name="locations"/> collection.</returns>
		/// <exception cref="ArgumentNullException">when <paramref name="locations"/> are not specified.</exception>
		public static LocationRectangle GetScaledOuterRectangle(this IEnumerable<Location> locations, double scaleFactor)
		{
			return locations
				.GetOuterRectangle()
				.Scale(scaleFactor);
		}

		/// <summary>
		/// Calculates the outer rectangle containing all the locations in the <paramref name="locations"/> collection
		/// and scales it applying the default scale factor (0.5).
		/// </summary>
		/// <param name="locations">The locations collection.</param>
		/// <returns>The rectangle containing all the locations in the <paramref name="locations"/> collection.</returns>
		/// <exception cref="ArgumentNullException">when <paramref name="locations"/> are not specified.</exception>
		public static LocationRectangle GetScaledOuterRectangle(this IEnumerable<Location> locations)
		{
			return locations
				.GetOuterRectangle()
				.Scale(0.5);
		}

		/// <summary>
		/// Scales the specified rectangle.
		/// </summary>
		/// <param name="rectangle">The rectangle to scale.</param>
		/// <param name="scaleFactor">The scale factor to apply.</param>
		/// <returns>A new scaled rectangle.</returns>
		/// <exception cref="ArgumentNullException">when <paramref name="rectangle"/> is not specified.</exception>
		public static LocationRectangle Scale(this LocationRectangle rectangle, double scaleFactor)
		{
			if (rectangle == null) throw new ArgumentNullException("rectangle");

			var nwCorner = rectangle.NorthWest;
			var seCorner = rectangle.SouthEast;
			var scaleFactorLatitude = (nwCorner.Latitude - seCorner.Latitude) * scaleFactor;
			var scaleFactorLongitude = (seCorner.Longitude - nwCorner.Longitude) * scaleFactor;

			nwCorner = new Location(nwCorner.Latitude + scaleFactorLatitude, nwCorner.Longitude - scaleFactorLongitude);
			seCorner = new Location(seCorner.Latitude - scaleFactorLatitude, seCorner.Longitude + scaleFactorLongitude);

			return new LocationRectangle(nwCorner, seCorner);
		}
	}
}
